﻿#include "ipaddr.h"

/**
 * @brief 将ip地址设置为缺省值
 */
void ipaddr_set_any(ipaddr_t *ip)
{
    ip->type = IPADDR_V4;
    ip->q_addr = 0;
}

/**
 * @brief 将字符串转换为ip地址
 * @param ip 需要被改变的目标ip地址
 * @param str 字符串
 */
net_err_t ipaddr_from_str(ipaddr_t *ip, const char *str)
{
    if (!ip || !str)
        return NET_ERR_PARAM;

    uint8_t *ip_p = ip->addr;
    uint8_t tmp_addr = 0;
    char c;
    while ((c = *str++) != '\0')
    {
        if (c >= '0' && c <= '9')
        {
            tmp_addr = tmp_addr * 10 + (c - '0');
        }
        else if (c == '.')
        {
            *ip_p++ = tmp_addr;
            tmp_addr = 0;
        }
        else
        {
            return NET_ERR_PARAM;
        }
    }

    *ip_p = tmp_addr;
    return NET_ERR_OK;
}

/**
 * @brief ip地址的拷贝操作
 * @param dest 目的ip地址
 * @param src 源ip地址
 */
void ipaddr_copy(ipaddr_t *dest, const ipaddr_t *src)
{
    if (!dest || !src)
        return;

    dest->q_addr = src->q_addr;
    dest->type = src->type;
}

/**
 * @brief 获取一个缺省ip地址
 */
ipaddr_t *ipaddr_get_any()
{
    static ipaddr_t any_ipaddr = {.q_addr = 0, .type = IPADDR_V4};
    return &any_ipaddr;
}

/**
 * @brief 比较两个ip地址是否相同
 */
bool ipaddr_is_equal(const ipaddr_t *ipaddr1, const ipaddr_t *ipaddr2)
{
    return ipaddr1->q_addr == ipaddr2->q_addr;
}

/**
 * @brief 将ip地址写入到指定的内存里
 * @param ipaddr ip地址
 * @param buf 写入ip地址的内存
 */
void ipaddr_to_buf(const ipaddr_t *ipaddr, uint8_t *buf)
{
    *(uint32_t *)buf = ipaddr->q_addr;
}

/**
 * @brief 从buf中获取ip地址
 */
ipaddr_t ipaddr_from_buf(const uint8_t *buf, ip_type_t type)
{
    ipaddr_t ipaddr;
    ipaddr.type = type;
    if (IPADDR_V4 == type)
    {
        ipaddr.q_addr = *(uint32_t *)buf;
    }

    return ipaddr;
}

/**
 * @brief 根据掩码获取主机号
 * @param ipaddr ip地址
 * @param netmask 掩码
 * @return 主机号
 */
ipaddr_t ipaddr_get_host(const ipaddr_t *ipaddr, const ipaddr_t *netmask)
{
    ipaddr_t hostid;
    hostid.q_addr = ipaddr->q_addr & (~netmask->q_addr);
    return hostid;
}

/**
 * @brief 根据掩码获取网络号
 * @param ipaddr ip地址
 * @param netmask 掩码
 * @return 网络号
 */
ipaddr_t ipaddr_get_net(const ipaddr_t *ipaddr, const ipaddr_t *netmask)
{
    ipaddr_t netid;
    netid.q_addr = ipaddr->q_addr & netmask->q_addr;
    return netid;
}

/**
 * @brief 判断ip地址是否为本地广播地址 255.255.255.255
 */
bool ipaddr_is_local_broadcast(const ipaddr_t *ipaddr)
{
    return ipaddr->q_addr == BROADCAST_IPV4_ADDR;
}

/**
 * @brief 判断ip地址是否为定向广播地址 x.x.x.255之类
 */
bool ipaddr_is_direct_broadcast(const ipaddr_t *ipaddr, const ipaddr_t *netmask)
{
    ipaddr_t hostid = ipaddr_get_host(ipaddr, netmask);
    return hostid.q_addr == (BROADCAST_IPV4_ADDR & (~(netmask->q_addr)));
}

/**
 * @brief 判断ip地址的目标与网络接口的ip地址是否符合
 */
bool ipaddr_is_match(const ipaddr_t *dest_ip, const ipaddr_t *src_ip, const ipaddr_t *netmask)
{
    if (ipaddr_is_local_broadcast(dest_ip))
    {
        return true;
    }

    if (ipaddr_is_direct_broadcast(dest_ip, netmask))
    {
        ipaddr_t dest_netid = ipaddr_get_net(dest_ip, netmask);
        ipaddr_t src_netid = ipaddr_get_net(src_ip, netmask);
        return dest_netid.q_addr == src_netid.q_addr;
    }

    return dest_ip->q_addr == src_ip->q_addr;
}

/**
 * @brief 判断ip地址是否为缺省ip地址
 */
bool ipaddr_is_any(const ipaddr_t *ipaddr)
{
    return ipaddr_get_any()->q_addr == ipaddr->q_addr;
}

/**
 * @brief 获取ip地址中为1的位数
 */
int ipaddr_one_cnt(const ipaddr_t *ipaddr)
{
    int cnt = 0;
    uint32_t q_addr = ipaddr->q_addr;
    while(q_addr)
    {
        if(q_addr & 0x80000000)
        {
            ++cnt;
        }
        q_addr = q_addr << 1;
    }

    return cnt;
}